﻿/************************************************************************
 * CoreDES - A small and core library for discrete event systems
 * Copyright (C) 2012-2013 Ali Khalili (khalili_DOT_ir_@SIGN_gmail_DOT_com)
 * **********************************************************************
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License (LGPL) published 
 * by the Free Software Foundation; either version 2.1 of the License, or (at your
 * option) any later version. This program is distributed without any
 * warranty. See the GNU Lesser General Public License for more details. 
 * ***********************************************************************
 * File         :     CoreDES\Execution\Procedure.cs
 * Description  :     a wrapper for System.Reflection.MethodInfo where there is no return value
 * Change log   :     -oct 2013: initial version
 * To Do        :
 ************************************************************************/
using System;
using System.Reflection;

namespace CoreDES.Execution
{
    /// <summary>
    /// A procedure with unknown number of parameters or unknown. 
    /// If number of parameters is zero, it can also be called by handler
    /// <remarks>Procedure is like a function but does not return any value</remarks>
    /// </summary>
    public class Procedure : ExecutableMethod
    {
        /// <summary>
        /// Deligate handler (executing by delegate is much more faster than executing by reflection
        /// </summary>
        delegate void myDeligate();

        /// <summary>
        /// the delegate handler
        /// </summary>
        myDeligate funcHandle;

        /// <summary>
        /// It is not allowed!
        /// </summary>
        protected Procedure()
        {
            //* nothing
        }

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="sig">procedure signiture</param>
        //public Procedure(MethodSigniture sig)
        //{
        //    if (!sig.IsProcedure)
        //        throw new Exception("The signiture is related to a function not to procedure!");
        //    this.signiture = sig;
        //    this.handler = null;
        //}


        //public void Execute(params object[] pars)
        //{
        //    handler.Invoke(target, new object[] { pars });
        //}

        public void ExecuteByHandler()
        {
            if (funcHandle != null)
                funcHandle();
            else
                throw new Exception();
        }

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="handler">the handler</param>
        /// <param name="target">the target object</param>
        public Procedure(MethodInfo handler, object target = null)
        {
            this.handler = handler;
            if (target != null)
            {
                this.target = target;

                if (handler.GetParameters().Length == 0)
                {
                    SetHandler(handler, target);
                }
                else
                    funcHandle = null;
            }
            //signiture = ExtracrSigniture();
        }

        public virtual bool IsExecutableByDelegate
        {
            get
            {
                return (funcHandle != null);
            }
        }

        private void SetHandler(MethodInfo method, object target)
        {
            funcHandle = (myDeligate)Delegate.CreateDelegate(typeof(myDeligate), target, method, false);
            if (funcHandle == null)
                throw new Exception("Error: procedure not resolved!");
        }
    }

    //**********************************************************************************************************

    /// <summary>
    /// A procedure with one parameter
    /// </summary>
    /// <typeparam name="RetType">type of return value</typeparam>
    /// <typeparam name="P1Type">type of the -only- parameter</typeparam>
    public class Procedure<P1Type> : Procedure
    {
        /// <summary>
        /// 
        /// </summary>
        /// <param name="myParam1"></param>
        delegate void myDeligate(P1Type myParam1);

        /// <summary>
        /// 
        /// </summary>
        myDeligate funcHandle;

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="m">the method info related to procedure</param>
        /// <param name="target">the target of execution</param>
        public Procedure(MethodInfo m, object target)
            : base(m)
        {
            SetHandler(m, target);
        }

        private void SetHandler(MethodInfo method, object target)
        {
            funcHandle = (myDeligate)Delegate.CreateDelegate(typeof(myDeligate), target, method, false);
            if (funcHandle == null)
                throw new Exception("Error: procedure not resolved!");
        }

        public void ExecuteByHandle(P1Type p1)
        {
            funcHandle(p1);
        }

        public override bool IsExecutableByDelegate
        {
            get
            {
                return true;
            }
        }
    }


    //**********************************************************************************************************

    /// <summary>
    /// A procedure with two parameters
    /// </summary>
    /// <typeparam name="RetType">type of return value</typeparam>
    /// <typeparam name="P1Type">type of first parameters</typeparam>
    /// <typeparam name="P2Type">type of second parameters</typeparam>
    public class Procedure<P1Type, P2Type> : Procedure
    {
        delegate void myDeligate(P1Type myParam1, P2Type myParam2);
        myDeligate funcHandle;

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="m">the method info</param>
        /// <param name="target">the target object</param>
        public Procedure(MethodInfo m, object target)
            : base(m)
        {
            SetHandler(m, target);
        }

        private void SetHandler(MethodInfo method, object target)
        {
            funcHandle = (myDeligate)Delegate.CreateDelegate(typeof(myDeligate), target, method, false);
            if (funcHandle == null)
                throw new Exception("Error: procedure not resolved!");
        }

        public void ExecuteByHandle(P1Type p1, P2Type p2)
        {
            funcHandle(p1, p2);
        }
    }
}
